package zdream.control.region;

import java.util.Objects;

import zdream.utils.math.Rectangle;

/**
 * <p>房间
 * </p>
 *
 * @author Zdream
 * @since 0.0.1
 * @date
 *   2019-05-18 (created)
 *   2022-06-05 (last modified)
 */
public class Room {
	public final Region region;
	public final int id;

	public Room(Region region, int id) {
		super();
		this.region = Objects.requireNonNull(region);
		this.id = id;
	}

	/**
	 * 左下角这个点在 {@link Region} 中的位置. 单位: 块
	 */
	public int offsetX, offsetY;

	/**
	 * 房间的宽高. 单位: 块
	 */
	public int width, height;

	/**
	 * [x][y]
	 * 地形数据
	 */
	public byte[][] terrains;

	/**
	 * [x][y]
	 * 填充物数据. 最重要的填充物就是水.
	 * <p>当 {@code fillers[x][y] & ITerrainStatic.FILLER_WATER != 0} 时,
	 * 这个方块将判定为有水.
	 * </p>
	 */
	public byte[][] fillers;

	/**
	 * <p>地图四个方向和其它的房间相通的. 这里考虑当前房间边缘的哪些块可以通到其它房间, 房间号是多少.
	 * <p>注意, 所有跨区域的房间都是懒加载的. 只有当角色进入相关的房间, 这些跨区域的门才会加载进来.
	 * 系统需要读 {@link Region#points} 中的 {@link InterestPoint} 参数, 来初始化这些门的信息
	 * </p>
	 * 如果没有房间任何向外的门, gates = null
	 */
	public Gate[] gates;

	/**
	 * 所有敌人怪物点位
	 */
	public FoeSpawnPoint[] foes;

	/**
	 * 所有场的合集
	 */
	public FieldSpec[] fields;

	/**
	 * 查看一个方形是否在该房间范围内, 或者和该房间的区域重合. 不考虑碰边的情况
	 * @param bx
	 *   这个方形左下角在 {@link Region} 中的横坐标, 单位: 块
	 * @param by
	 *   这个方形左下角在 {@link Region} 中的纵坐标, 单位: 块
	 * @param bw
	 *   这个方形的宽, 单位: 块
	 * @param bh
	 *   这个方形的高, 单位: 块
	 */
	public boolean overlaps(float bx, float by, float bw, float bh) {
		return offsetX < bx + bw
				&& offsetX + width > bx
				&& offsetY < by + bh
				&& offsetY + height > by;
	}

	/**
	 * 查看一个点是否在该房间范围内, 或者压住房间的边缘线.
	 * @param x
	 *   这个点在 {@link Region} 中的横坐标, 单位: 块
	 * @param y
	 *   这个点在 {@link Region} 中的纵坐标, 单位: 块
	 */
	public boolean contain(float x, float y) {
		return this.offsetX <= x && this.offsetX + this.width >= x && this.offsetY <= y && this.offsetY + this.height >= y;
	}

	/**
	 * 查看一个点是否在该房间范围内, 或者压住房间的边缘线.
	 * @param bx
	 *   这个点在当前房间中的横坐标, 单位: 块
	 * @param by
	 *   这个点在当前房间中的纵坐标, 单位: 块
	 * @return
	 *   1: 房间内
	 *   0: 在边缘线
	 *   -1: 房间外
	 */
	public int containInRoomForBlock(float bx, float by) {
		if (bx > width || bx < 0 || by > height || by < 0) {
			return -1;
		}
		return (0 < bx && width > bx && 0 < by && height > by) ? 1 : 0;
	}

	/**
	 * 查看一个区域点块是否在该房间范围内
	 * @param x
	 *   这个点在 {@link Region} 中的横坐标, 单位: 格子
	 * @param y
	 *   这个点在 {@link Region} 中的纵坐标, 单位: 格子
	 */
	public boolean contain(int x, int y) {
		return this.offsetX <= x && this.offsetX + this.width > x && this.offsetY <= y && this.offsetY + this.height > y;
	}

	public Rectangle transformFromRegionPosition(Rectangle from) {
		return new Rectangle(from.x - offsetX, from.y - offsetY, from.width, from.height);
	}

	public float transformFromRegionX(float xInRegion) {
		return xInRegion - offsetX;
	}

	public float transformFromRegionY(float yInRegion) {
		return yInRegion - offsetY;
	}

	@Override
	public String toString() {
		return String.format("Room:%s[%d]", region == null ? "" : region.name, id);
	}
}
